/* 泛型约束：关键字extends */

//1.简单类型约束
function fun<T extends string>(value:T):T{
    return value;
}

let res1 = fun('Make');  //这里参数只能传入string类型的
console.log("简单类型约束： ",res1,"\n");


//2.联合类型约束
function fun1<T extends string | boolean>(value:T):T{
    return value;
}

let res2 = fun1("Jack");  //fun1参数只能是string或者boolean类型
let res3 = fun1(false);
console.log("联合类型约束： ",res2);
console.log("联合类型约束： ",res3,"\n");


//3.对象属性约束
interface People {
    name:string,
    age:number,
    height?:number
}
    //keyof:获取一个类型（通常是对象类型）的所有键（即属性名）
function fun2<T extends People,P extends keyof T>(obj:T,value:P){
    return obj[value];
}

let res4 = fun2({name:"Amy",age:15},"age"); //这里前面对象没有 height 属性，所以后面value不能取
let res5 = fun2({name:"Amy",age:15,"height":175},"height"); //这里前面对象有，所有可取
console.log("对象属性约束： ",res4);
console.log("对象属性约束： ",res5,"\n");


//4.泛型属性约束
function fun3<T,K extends keyof T>(obj:T,key:K):T[K]{
    return obj[key];
}

let res6 = fun3(15.42,"toFixed"); //这里前面是 number 类型，则后一个参数是number类型的方法或者属性
let res7 = fun3("Amy","toString"); //这里同理，后面是string的方法或者属性
//如果key是属性，则输出结果；如果key是方法名，则输出 [Function: 方法名]
let res8 = fun3("Zip","length"); //这里length是string的属性
console.log("泛型属性约束： ",res6);
console.log("泛型属性约束： ",res7);
console.log("泛型属性约束： ",res8,"\n");
